import { uploadFile } from '@/api'
import store from '../store'
import tinymce from 'tinymce/tinymce'
import { v4 as uuid } from 'uuid'
import { Message } from 'element-ui'
import CopyToClipboard from 'copy-to-clipboard'
import { refreshTableNumbers } from '@/utils/plugins/table/noteSetting'
import { refreshFigureNumbers } from '@/utils/plugins/image/figureSetting'
import { pasteUpdatedDOM } from './paste'

/**
 * 向节点第一个元素前插入新元素
 * @param {*} node 需要插入的子节点
 * @param {*} parentNode 父节点
 */
export function prependChild(node, parentNode) {
  if (parentNode.hasChildNodes()) {
    parentNode.insertBefore(node, parentNode.firstChild)
  } else {
    parentNode.appendChild(node)
  }
}

export function addRevisionLines(editor) {
  const revisionLineIds = store.state.xmleditor.revisionLineIds
  editor.dom
    .select('#tinymce>.page-wrapper .page-sheet [data-id]')
    .filter((node) => revisionLineIds?.includes(node.dataset.id) || revisionLineIds?.includes(node.dataset.blockId))
    .forEach((node) => editor.dom.addClass(node, 'is-revised'))
}

export function onNewBlock(editor) {
  editor.on('NewBlock', function ({ newBlock }) {
    console.debug('---NewBlock---', newBlock)
    if (newBlock?.nodeName === 'P') {
      if (tinymce.activeEditor.dom.getParent(newBlock, '.variables')) {
        editor.dom.setAttribs(newBlock, { 'data-id': uuid() })
        return
      }
      if (tinymce.activeEditor.dom.getParent(newBlock, '.item_list')) {
        // 在列项的子元素后enter
        return
      }
      if (newBlock.parentElement?.nodeName === 'P') {
        // 如果段落中只包含了纯文字，则在末尾enter后会新起一个平级的P标签
        // 如果段落中包含了<span>或其他元素，在<span>后面按enter会出现P标签嵌套P标签的情况，此时需要修正数据结构：将新的block放在父级之后，并将父级的内容还原
        const parent = newBlock.parentElement
        const html = newBlock.previousElementSibling?.innerHTML || '<br>'
        const newBlockHtml = newBlock.nextElementSibling?.innerHTML || newBlock.innerHTML || '<br>'
        const paragraph = editor.dom.create(
          'p',
          {
            'data-block-id': uuid(),
            'data-id': uuid(),
            'data-type': 'paragraph'
          },
          newBlockHtml
        )
        editor.dom.insertAfter(paragraph, parent)
        editor.selection.setCursorLocation(paragraph, 0)
        parent.innerHTML = html
      } else if (
        (newBlock.parentElement?.nodeName === 'TD' && newBlock.parentElement?.dataset?.type === 'table_note') ||
        newBlock?.dataset?.type === 'figure_note'
      ) {
        console.debug('标注、图注')
      } else {
        editor.dom.setAttribs(newBlock, {
          'data-block-id': uuid(),
          'data-id': uuid(),
          'data-type': 'paragraph',
          class: ''
        })
      }
      store.commit('xmleditor/UPDATE_DOC_STRUCTURE')
    }
  })
}
export function onPaste(editor) {
  editor.on('paste', async function (evt) {
    console.debug('---on paste---', evt)
    evt.preventDefault()
    const node = editor.selection.getNode()
    // 不可编辑的元素不支持粘贴
    if (node.contentEditable === 'false') return
    const paragraphTypes = [
      'paragraph',
      'item_list',
      'example',
      'item_note',
      'table_note',
      'table_footnote',
      'figure_note',
      'figure_footnote',
      'chapter',
      'chapter_title_zh',
      'chapter_title_en'
    ]
    // 章节标题处、图题、表题、附录第三行处也需支持粘贴纯文本
    const isParagraph =
      paragraphTypes.indexOf(node.dataset?.type) > -1 ||
      editor.dom.getParent(
        node,
        paragraphTypes.map((i) => `p[data-type="${i}"]`).join(',') +
          ',p.caption,p.data-content-image-caption,p.annex-title,p.list-title'
      )

    // 是否不允许在列项中插入(列项不能被其他结构化数据打断)
    const disbleInsertInBullet =
      node.dataset.type === 'item_list' && node.nextElementSibling?.dataset?.type === 'item_list'

    const textHTML = (evt.clipboardData || window.clipboardData).getData('text/html')
    let htmlStr
    try {
      htmlStr = decodeURIComponent(textHTML)
    } catch (err) {
      htmlStr = textHTML
    }
    if (htmlStr) {
      pasteUpdatedDOM(htmlStr, editor)
      return
    }
    /** Deprecated */
    if (htmlStr) {
      // 解析从word复制的表格
      const docDom = new DOMParser().parseFromString(htmlStr, 'text/html')
      // 粘贴表格
      const tableDom = docDom?.querySelector?.('table')
      if (tableDom) {
        if (disbleInsertInBullet) {
          return Message.warning({
            message: '列项中暂不支持插入表格',
            showClose: true
          })
        }
        // 支持编辑器内部的表格复制粘贴
        return insertTableAfterPaste(tableDom, editor)
      }

      // 粘贴图结构化块
      const figureBlock = docDom?.querySelector?.('div[data-type="figure"')
      if (figureBlock && !disbleInsertInBullet) {
        // 更新id，避免重复
        figureBlock.dataset.id = uuid()
        figureBlock.dataset.blockId = uuid()
        const notes = figureBlock.querySelectorAll('p')
        notes?.length > 0 &&
          Array.from(notes).forEach((p) => {
            p.dataset.id = uuid()
            if (p.dataset.noteId) {
              p.dataset.noteId = uuid()
            }
          })
        return insertElementAfterBlock(figureBlock, editor)
      }

      // 粘贴图片
      const imgRegex = /<img[^>]+>/g
      const imgTags = htmlStr.match(imgRegex)
      const srcRegex = /src=['"]?([^'"]*)['"]?/
      if (imgTags?.length > 0 && !disbleInsertInBullet) {
        imgTags.forEach((item) => {
          const srcAttr = item.match(srcRegex)[1]
          !srcAttr.includes('file://') && insertFigureAfterPaste(srcAttr, editor)
        })
      }

      // 粘贴非空白段落, html中的段落粘贴会多出额外的错误内容，故使用items中的文本进行粘贴
      /*
      const _paragraphs = Array.from(docDom?.querySelectorAll?.('p') || []).filter((i) => i.textContent?.length > 0)
      if (_paragraphs?.length) {
        return insertParagraphAfterPaste(
          editor,
          _paragraphs.map((i) => i.textContent),
          isParagraph,
          disbleInsertInBullet
        )
      }
      */
    }

    // 实现复制图片文件内容粘贴到编辑器
    const items = (evt.clipboardData || window.clipboardData).items
    if (!disbleInsertInBullet && items?.length > 0) {
      for (const item of items) {
        if (item.kind === 'file' && item.type.includes('image/')) {
          const blob = item.getAsFile()
          console.log('file-png', blob)
          if (!blob) continue
          try {
            const formData = new FormData()
            formData.append('file', blob, '_')
            uploadFile(formData).then(({ data }) => {
              insertFigureAfterPaste(
                window.location.origin + '/prod-api/editor/file/download/' + data,
                editor
              )
            })
          } catch (error) {
            console.error(error)
          }
        } else if (item.kind === 'string' && item.type.includes('plain')) {
          item.getAsString((paste) => {
            const pastedTexts = paste.split('\n').filter((i) => i.length > 0)
            insertParagraphAfterPaste(editor, pastedTexts, isParagraph, disbleInsertInBullet)
          })
        }
      }
    }
    /*
    const paste = (evt.clipboardData || window.clipboardData).getData('text')
    if (!paste) return
    // 当前的光标在段落、示例、注、列项上，则复制的文字内容的第一段放在当前行
    const pastedTexts = paste.split('\n').filter((i) => i.length > 0)
    insertParagraphAfterPaste(editor, pastedTexts, isParagraph, disbleInsertInBullet)
    */
  })
  editor.on('cut', function (evt) {
    console.debug('---on cut---', evt)
    if (evt.target?.nodeName === 'IMG' && evt.path[2]?.dataset.type === 'figure') {
      // 如果剪切的是图片，直接将图结构化块放在内存中
      try {
        CopyToClipboard(encodeURIComponent(evt.path[2].outerHTML))
      } catch (error) {
        console.log('剪切图片失败', error)
      }
      editor.dom.remove(evt.path[2])
    }
  })
}
function convertBase64ToBlob(base64) {
  var base64Arr = base64.split(',')
  var imgtype = ''
  var base64String = ''
  if (base64Arr.length > 1) {
    base64String = base64Arr[1]
    imgtype = base64Arr[0].substring(base64Arr[0].indexOf(':') + 1, base64Arr[0].indexOf(';'))
  }
  var bytes = atob(base64String)
  var bytesCode = new ArrayBuffer(bytes.length)
  var byteArray = new Uint8Array(bytesCode)
  for (let i = 0; i < bytes.length; i++) {
    byteArray[i] = bytes.charCodeAt(i)
  }

  return new Blob([bytesCode], { type: imgtype })
}

export async function getImageSrc(image) {
  const blob = convertBase64ToBlob(image.url || image.src)
  const formData = new FormData()
  formData.append('file', blob, '_')
  const { data } = await uploadFile(formData)
  console.log('window.location.origin',window.location.origin)
  // return 'http://172.16.41.11/prod-api/editor/file/download/' + data
  return window.location.origin + '/prod-api/editor/file/download/' + data
}

export async function updateInlineFormula(imgId, image, latex = '') {
  const width = parseInt(image.width / 2)
  const height = parseInt(image.height / 2)
  const src = await getImageSrc(image)
  const img = tinymce.activeEditor.getDoc()?.querySelector(`[data-id="${imgId}"]`)
  tinymce.activeEditor.dom.setAttribs(img, { 'data-latex': latex, src, width, height })
}

export async function updateFormula(nodeId, image, latex = '', container) {
  let doc = tinymce.activeEditor.getDoc()
  if (container) {
    doc = document.querySelector(container)
  }

  const width = parseInt(image.width)
  const height = parseInt(image.height)
  const node = doc.querySelector(`[data-id="${nodeId}"]`)
  const img = node.querySelector('img')
  const dotline = node.querySelector('.dotline')
  tinymce.activeEditor.dom.setStyle(img, 'margin-left', 'calc(50% - ' + width / 4 + 'px)')
  tinymce.activeEditor.dom.setStyle(dotline, 'height', height / 4 + 'px')
  tinymce.activeEditor.dom.setAttribs(node, {
    'data-latex': latex,
    'data-image-width': width,
    'data-image-height': height
  })
  const src = await getImageSrc(image)
  tinymce.activeEditor.dom.setAttribs(img, { 'data-img-latex': latex, src, width: width / 2, height: height / 2 })
}

export function removeAllClass() {
  ;[...document.querySelectorAll('.page-sheet')].forEach((node) => {
    node.classList.add('noneditable')
    node.setAttribute('contenteditable', false)
    node.querySelectorAll('div, p, span, table, img, sup, sub').forEach((i) => {
      i.setAttribute('contenteditable', false)
    })
  })
  ;['compare-remove', 'compare-remove'].forEach((cl) => {
    document
      .querySelector(`.left-wrapper`)
      .querySelectorAll(`.${cl}`)
      .forEach((node) => node.classList.remove(cl))

    document
      .querySelector(`.right-wrapper`)
      .querySelectorAll(`.${cl}`)
      .forEach((node) => node.classList.remove(cl))
  })
}

export function syncScroller() {
  let nodes = Array.prototype.filter.call(arguments, (item) => item instanceof HTMLElement)
  let max = nodes.length
  if (!max || max === 1) return
  let sign = 0 // 用于标注

  function event() {
    if (!sign) {
      // 标注为 0 时 表示滚动起源
      sign = max - 1
      let top = this.scrollTop
      let left = this.scrollLeft
      for (const node of nodes) {
        // 同步所有除自己以外节点
        if (node == this) continue
        node.scrollTo(left, top)
      }
    } else --sign // 其他节点滚动时 标注减一
  }

  nodes.forEach((ele) => {
    ele.addEventListener('scroll', event)
  })

  return () => {
    nodes.forEach((ele) => {
      ele.removeEventListener('scroll', event)
    })
  }
}

// 更新附录中的表图编号
export function refreshAnnexNumber(editor) {
  const editorDoc = editor.getDoc?.()
  const pages = editorDoc?.querySelectorAll?.('.page-sheet.annex')
  if (!pages.length) return
  Array.from(pages).forEach((pageDom) => {
    const tables = pageDom?.querySelectorAll?.('table.data-content-table[data-type="table"]')
    const annexNumber = pageDom.querySelector('[data-annex-number]')?.dataset.annexNumber
    if (tables?.length > 0) {
      Array.from(tables).forEach((tableDom) => {
        tableDom.setAttribute('data-table-annex-number', annexNumber)
        const captions = tableDom.querySelectorAll('caption p.caption')
        if (!captions.length) return
        Array.from(captions).forEach((captionDom) => {
          captionDom.setAttribute('data-table-annex-number', annexNumber)
        })
      })
    }
    const figures = pageDom?.querySelectorAll?.('div.data-content-image-wrapper[data-type="figure"]')
    if (figures?.length > 0) {
      Array.from(figures).forEach((figureDom) => {
        figureDom.setAttribute('data-figure-annex-number', annexNumber)
        const captions = figureDom.querySelectorAll('p.data-content-image-caption')
        if (!captions.length) return
        Array.from(captions).forEach((captionDom) => {
          captionDom.setAttribute('data-figure-annex-number', annexNumber)
        })
      })
    }
  })
}

// 更新页眉上的页数
export function refreshPageNumberInHeader(editor) {
  setTimeout(() => {
    const editorDoc = editor.getDoc?.()
    const languageType = store.getters.languageType
    const etsi = store.getters.filePropertyName === 'ETSI'
    // 总页数包括：目次、前言、引言、文件的正文、附录、参考文献和索引
    const arr1 = ['contents', 'foreword', 'introduction', 'reference', 'page-content', 'index', 'annex', 'reference']
    // 新增英文索引
    const doms = editorDoc?.querySelectorAll?.([...arr1, 'indexEn'].map((i) => `.page-sheet.${i}`).join())
    const totalPage = doms?.length || 0
    if (totalPage > 0) {
      Array.from(doms).forEach((pageDom, index) => {
        const pageHeader = pageDom.querySelector('.page_header .page-number')
        // ETSI 都是中文
        if (languageType === 'both' && !etsi) {
          editor.dom.setHTML(pageHeader, `SHEET ${index + 1} OF ${totalPage}`)
        } else {
          editor.dom.setHTML(pageHeader, `第 ${index + 1} 页 共 ${totalPage} 页`)
        }
      })
    }
  }, 200)
}

export function setCursorLocation(editor, target, step = 0) {
  const childNodes = target.parentNode?.childNodes || []
  let pos = 0
  for (let i = 0; i < childNodes.length; i++) {
    const el = childNodes[i]
    if (el === target) {
      pos = i
      break
    }
  }
  editor.selection.setCursorLocation(target.parentNode, pos + step)
}

// 初始化的时候添加enter的keydown事件，用于阻止选中不可编辑的元素后按enter **这个监听在setup里面才会生效
export function addSetupListeners(editor) {
  editor.on('keydown', function (event) {
    const keyArr = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Tab']
    const node = editor.selection.getNode()
    const rng = editor.selection.getRng()
    if (keyArr.includes(event.key)) {
      if (rng?.collapsed) {
        if (rng?.startContainer?.nodeType === 3) {
          const { previousElementSibling, nextElementSibling } = rng?.startContainer || {}
          if (event.key === 'ArrowLeft') {
            if (rng?.startContainer?.length === 1 && rng?.startOffset <= 1) {
              if (editor.dom.is(previousElementSibling, 'span')) {
                setCursorLocation(editor, previousElementSibling, 0)
                event.preventDefault()
                return false
              }
            }
          }

          if (event.key === 'ArrowRight') {
            if (rng?.startContainer?.length === 1 && rng?.startOffset === 0) {
              if (editor.dom.is(nextElementSibling, 'span')) {
                setCursorLocation(editor, nextElementSibling, 1)
                event.preventDefault()
                return false
              }
            }
          }
        }
      }
      if (!editor.dom.is(node, 'p')) {
        event.preventDefault()
        return false
      }
    }
    // 禁止在术语块中间按Enter
    if (event.key === 'Enter') {
      const isTermBlock = (el) => editor.dom.is(el, '[data-type="terms"]')
      if (isTermBlock(node.previousElementSibling) && isTermBlock(node.nextElementSibling)) {
        console.debug('===禁止在术语块中间按Enter===')
        Message.warning({ message: '请不要拆分多个术语', showClose: true })
        event.preventDefault()
        return false
      }
    }
    // 禁止在公式中按Enter
    if (event.key === 'Enter' && editor.dom.getParent(node, '[data-type="formula"]')) {
      console.debug('===禁止在公式中按Enter===')
      event.preventDefault()
      return false
    }
    // 禁止在上下标中按Enter
    if (event.key === 'Enter' && editor.dom.getParent(node, 'sup,sub')) {
      Message.warning({ message: '上下标中不支持换行', showClose: true })
      console.debug('===禁止在上下标中按Enter===')
      event.preventDefault()
      return false
    }
    if (event.key === 'Enter') {
      if (
        node.contentEditable === 'false' ||
        node.classList.contains('noneditable') ||
        node?.dataset?.type === 'table_footnote'
      ) {
        console.log('===event prevented contentEditable=false ===')
        event.preventDefault()
        return false
      }
      if (node.classList.contains('page_body')) {
        if (node.contentEditable !== 'false' && editor.selection.getEnd()?.nodeName === 'TABLE') {
          // 光标在表格后面，enter未获取到节点时，主动添加空行
          console.log('===event prevented cursor after table ===')
          editor.insertContent(`<p data-type="paragraph" data-id="${uuid}" data-block-id="${uuid()}"><br></p>`)
        }
        event.preventDefault()
        return false
      }
    }
    if (event.key === 'Backspace') {
      // 表格的表题不允许被删除
      if (
        node.classList.contains('caption') &&
        editor.dom.getParent(node, 'table') &&
        node.textContent.replace(/[\u200B-\u200D\uFEFF]/g, '').length === 0
      ) {
        event.preventDefault()
        return false
      }
    }
    // TAB 键行为在段落内插入3个空格
    const captionNotTable = editor.dom.getParent(node, 'caption') || !editor.dom.getParent(node, 'table')
    if (event.key === 'Tab' && captionNotTable && editor.dom.is(node, 'p,span')) {
      editor.insertContent(`&nbsp;&nbsp;&nbsp;`)
      event.preventDefault()
      event.stopPropagation()
      return false
    }
  })
}

export function getTextWidth(text = '', font = '12pt 宋体') {
  const canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement('canvas'))
  const context = canvas.getContext('2d')
  context.font = font
  const metrics = context.measureText(text)
  return metrics.width
}

// 在block后面插入结构化块，避免嵌套，解析不出来
export function insertElementAfterBlock(element, editor) {
  const node = editor.selection?.getNode?.()
  if (!node) {
    return editor.insertContent(element.outerHTML)
  }
  let ancestor = editor.dom.getParent(node, 'table')
  if (ancestor) {
    // 插入在表格之后
    if (element.nodeName === 'P' && editor.dom.getParent(node, 'tbody p, thead p')) {
      // 表格内部支持多行文本粘贴
      return editor.dom.insertAfter(element, node)
    }
    return editor.dom.insertAfter(element, ancestor)
  }
  ancestor = editor.dom.getParent(node, 'div[data-type="figure"]')
  if (ancestor) {
    // 插入在图结构化块之后
    return editor.dom.insertAfter(element, ancestor)
  }
  if (node.nodeName === 'P' || ['paragraph', 'figure', 'table'].indexOf(node.dataset.type) > -1) {
    // 插入在段落、图、表后面
    return editor.dom.insertAfter(element, node)
  }
  ancestor = editor.dom.getParent(node, 'p')
  if (ancestor) {
    // 插入在段落的后面
    return editor.dom.insertAfter(element, ancestor)
  }
  editor.selection.setContent(element.outerHTML)
}

// 判断当前节点是否在引言或者附录中，读取其表格、图的编号以及样式名称
export function getAnnexIntroductionNumber(type, editor) {
  const currentNode = editor.selection.getNode()
  const annexParent = editor.dom.getParent(currentNode, '.page-sheet.annex')
  const introductionParent = editor.dom.getParent(currentNode, '.page-sheet.introduction')
  let annexNumber = null,
    className = ''
  if (annexParent) {
    annexNumber = annexParent.querySelector('[data-annex-number]')?.dataset.annexNumber
    className = type + '-annex'
  } else if (introductionParent) {
    className = type + '-introduction'
  }
  return { className, annexNumber }
}

// 粘贴图片，插入图结构化块
function insertFigureAfterPaste(dataSrc, editor) {
  const { annexNumber, className } = getAnnexIntroductionNumber('figure', editor)
  const languageType = store.getters.languageType
  let config = {
    'data-id': uuid(),
    class: 'data-content-image-wrapper ' + className,
    'data-block-id': uuid(),
    'data-type': 'figure'
  }
  const elm = editor.dom.create('div', config)
  if (annexNumber) {
    config['data-figure-annex-number'] = annexNumber
  }
  elm.innerHTML = `
    <p class="image-wrapper">
      <img src="${dataSrc}" />
    </p>
    <p class="data-content-image-caption zh"
      ${annexNumber ? `data-figure-annex-number="${annexNumber}"` : ''} data-id="${uuid()}">图题</p>
    ${languageType === 'both' ? `<p class="data-content-image-caption en" data-id="${uuid()}">xxx</p>` : ''}
  `
  insertElementAfterBlock(elm, editor)
  // 新增图片后，刷新正文内的图编号
  refreshFigureNumbers(editor)
}
// 粘贴表格，插入表格结构化块
function insertTableAfterPaste(tableDom, editor) {
  const rows = Array.from(tableDom.rows || [])
  if (!rows.length) return
  const { annexNumber, className } = getAnnexIntroductionNumber('table', editor)
  const languageType = store.getters.languageType
  let config = {
    'data-id': uuid(),
    class: 'data-content-table ' + className,
    'data-block-id': uuid(),
    'data-mce-selected': '1',
    'data-type': 'table',
    border: 1
  }
  if (annexNumber) {
    config['data-table-annex-number'] = annexNumber
  }
  const elm = editor.dom.create('table', config)

  if (tableDom.classList.contains('data-content-table')) {
    // 如果是从编辑器内部复制粘贴，只需替换所有相关的id
    const _html = tableDom.innerHTML
    let newHtml = _html.replace(/data-id="([^"]+)"/g, () => `data-id="${uuid()}"`)
    newHtml = newHtml.replace(/data-note-id="([^"]+)"/g, () => `data-note-id="${uuid()}"`)
    newHtml = newHtml.replace(/data-block-id="([^"]+)"/g, () => `data-block-id="${uuid()}"`)
    newHtml = newHtml.replace(/data-referred-id="([^"]+)"/g, () => `data-referred-id="${uuid()}"`)
    newHtml = newHtml.replace(/data-share-id="([^"]+)"/g, () => `data-share-id="${uuid()}"`)
    elm.innerHTML = newHtml
    Array.from(elm.querySelectorAll('caption p.caption')).forEach((item) => {
      if (annexNumber) {
        item.setAttribute('data-table-annex-number', annexNumber)
      } else {
        item.removeAttribute('data-table-annex-number')
      }
    })
  } else {
    // 从外部粘贴的表格
    let innerHTML = ''
    // 插入表格标题
    innerHTML += `
      <caption class="table_caption zh">
        <p class="caption zh" ${annexNumber ? `data-table-annex-number="${annexNumber}"` : ''}>表题</p>
        <p class="unit"><br></p>
      </caption>
    `
    if (languageType === 'both') {
      innerHTML += `
        <caption class="table_caption en">
          <p class="caption en" ${annexNumber ? `data-table-annex-number="${annexNumber}"` : ''}
            >Table title</p>
          <p class="unit"><br></p>
        </caption>
      `
    }
    const createTr = (tds) => {
      let h = `<tr data-id="${uuid()}">`
      tds.forEach((td) => {
        h += `<td width="${td.width}" data-id="${uuid()}" colSpan="${td.colSpan}" rowspan="${td.rowSpan}">`
        Array.from(td.childNodes || []).forEach((_paragraph) => {
          // 暂时只支持纯文本
          h += `<p data-id="${uuid()}" data-block-id="${uuid()}" data-type="paragraph">${
            _paragraph.textContent || '<br>'
          }</p>`
        })
        h += `</td>`
      })
      h += `</tr>`
      return h
    }
    // 解析表格正文的行和列
    // 设置表格第一行为表头，若有合并的多行，一起设为表头
    innerHTML += '<thead>'
    const thRowsCount = Array.from(rows[0].children).reduce((sum, td) => (td.rowSpan > sum ? td.rowSpan : sum), 1)
    for (let i = 0; i < rows.length; i++) {
      innerHTML += createTr(Array.from(rows[i].children))
      if (i === thRowsCount - 1) {
        innerHTML += '</thead><tbody>'
      }
    }
    innerHTML += '</tbody>'
    elm.innerHTML = innerHTML
  }
  insertElementAfterBlock(elm, editor)
  // 表格后面加一个空行占位，避免enter报错
  setTimeout(() => {
    const paragraph = editor.dom.create(
      'p',
      {
        'data-type': 'paragraph',
        'data-id': uuid(),
        'data-block-id': uuid()
      },
      '<br>'
    )
    editor.dom.insertAfter(paragraph, elm)
    // 添加表格后，刷新正文中的表格编号
    refreshTableNumbers(editor)
  }, 100)
}
// 粘贴段落
function insertParagraphAfterPaste(editor, pastedTexts, isParagraph, disbleInsertInBullet) {
  const node = editor.selection.getNode()
  const rng = editor.selection.getRng()
  const { startOffset, endOffset } = rng
  pastedTexts.forEach((pastedText, idx) => {
    // 当前的光标在段落、示例、注、列项、条标题上，则复制的文字内容的第一段放在当前行
    if (idx === 0 && isParagraph) {
      if (Math.abs(startOffset - endOffset) === node.textContent.length) {
        // 如选中了表题节点的全部文字，直接替换表题内容，避免整个节点被替换
        node.textContent = pastedText
        return
      }
      return editor.insertContent(pastedText)
    }
    const str = pastedText.replace(/\s*/g, '')
    if (disbleInsertInBullet || !str) return
    const pElm = editor.dom.create(
      'p',
      {
        'data-block-id': uuid(),
        'data-id': uuid(),
        'data-type': 'paragraph'
      },
      pastedText
    )
    insertElementAfterBlock(pElm, editor)
    editor.selection.setCursorLocation(pElm, 0)
  })
}
